#include "AudioEncoder.h"

AudioEncoder::AudioEncoder(const int channels, const int sampleRate, const int quality) :
	m_nAudioChannels(channels), m_nAudioSampleRate(sampleRate), m_nAudioQuality(quality)
{
	initVorbisInfo();
	initVorbisEncoder();
}

AudioEncoder::~AudioEncoder(void)
{
	uinitVorbisEncoder();
	vorbis_info_clear(m_lpVorbisInfo);
	free(m_lpVorbisInfo);
}

void AudioEncoder::initVorbisInfo()
{
	m_lpVorbisInfo = (vorbis_info*)malloc(sizeof(vorbis_info));
	vorbis_info_init(m_lpVorbisInfo);

	float quality = m_nAudioQuality * (1.1f) / 100 - 0.1;
	//if (vorbis_encode_init(m_lpVorbisInfo, m_nAudioChannels, m_nAudioSampleRate, -1, 96000, -1) < 0)
	if (vorbis_encode_init_vbr(m_lpVorbisInfo, m_nAudioChannels, m_nAudioSampleRate, quality) < 0)
		exit(1);
}

void AudioEncoder::initVorbisEncoder()
{
	m_lpVorbisState = (vorbis_dsp_state*)malloc(sizeof(vorbis_dsp_state));
	if (vorbis_analysis_init(m_lpVorbisState, m_lpVorbisInfo) < 0)
		exit(1);

	/* add a comment */
	vorbis_comment vc;
	vorbis_comment_init(&vc);
	vorbis_comment_add_tag(&vc, "Clip", TITLE_FORM_MAIN);

	ogg_packet header;
	ogg_packet header_comm;
	ogg_packet header_code;
	if (vorbis_analysis_headerout(m_lpVorbisState, &vc, &header, &header_comm, &header_code) < 0)
		exit(1);
	vorbis_comment_clear(&vc);

	m_lpHeaderPackets = createPacket(&header);
	m_lpHeaderPackets->next = createPacket(&header_comm);
	m_lpHeaderPackets->next->next = createPacket(&header_code);

	m_lpVorbisBlock = (vorbis_block*)malloc(sizeof(vorbis_block));
	if (vorbis_block_init(m_lpVorbisState, m_lpVorbisBlock) < 0)
		exit(1);
}

void AudioEncoder::uinitVorbisEncoder()
{
	vorbis_block_clear(m_lpVorbisBlock);
	free(m_lpVorbisBlock);

	vorbis_dsp_clear(m_lpVorbisState);
	free(m_lpVorbisState);
}

PacketList* AudioEncoder::headerPackets()
{
	PacketList *ret = clonePacket(m_lpHeaderPackets);
	PacketList *tmpDst = ret, *tmpSrc = m_lpHeaderPackets;

	while(tmpDst)
	{
		tmpDst->next = clonePacket(tmpSrc->next);
		tmpDst = tmpDst->next;
		tmpSrc = tmpSrc->next;
	}

	return ret;
}

PacketList * AudioEncoder::remainPackets()
{
	return 0;
}

PacketList * AudioEncoder::encodeAudio(const TYPE_SAMPLE_IN **data, const int size)
{
	/* expose the buffer to submit data */
	float **buffer = vorbis_analysis_buffer(m_lpVorbisState, size);

	/* uninterleave samples */
	for (int i=0; i<size; i++)
	{
		for (int j=0; j<m_nAudioChannels; j++)
		{
			buffer[j][i] = data[j][i];
		}
	}

	/* tell the library how much we actually submitted */
	vorbis_analysis_wrote(m_lpVorbisState, size);

	PacketList *ret = 0, *tmp = 0;
	ogg_packet ogg_pkg;
	while(vorbis_analysis_blockout(m_lpVorbisState, m_lpVorbisBlock) > 0)
	{
		/* analysis, assume we want to use bitrate management */
		if (vorbis_analysis(m_lpVorbisBlock, NULL) < 0)
			exit(1);
		if (vorbis_bitrate_addblock(m_lpVorbisBlock) < 0)
			exit(1);

		while (vorbis_bitrate_flushpacket(m_lpVorbisState, &ogg_pkg) > 0)
		{
			if (0 == ret)
			{
				tmp = ret = createPacket(&ogg_pkg);
				continue;
			}
			tmp->next = createPacket(&ogg_pkg);
			tmp = tmp->next;
		}
	}

	return ret;
}
